package org.javadatabasemigrations;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.javadatabasemigrations.exceptions.MigrationVersionExistsException;
import org.javadatabasemigrations.util.Validation;


public class MigrationRunner {

    List<Migration> migrations = new ArrayList<Migration>();

    Map<Version, Migration> migrationVersions = new HashMap<Version, Migration>();


    public void runToHighestVersion(final Database db) {

        Set<Version> versionSet = migrationVersions.keySet();
        List<Version> versions = new ArrayList<Version>(versionSet);
        Collections.sort(versions);

        for (Version version : versions) {

            Migration migration = migrationVersions.get(version);
            migration.performMigration(db);
            db.setVersion(version);
        }
    }


    public void addMigrations(final List<Migration> migrations) {

        Validation.notNull(migrations);
        for (Migration migration : migrations) {
            addMigration(migration);
        }
    }


    public void addMigration(final Migration migration) {

        Validation.notNull(migration);

        Version version = MigrationUtils.getMigrationVersion(migration
                .getClass());

        if (versionExists(version)) {
            throw new MigrationVersionExistsException(
                "Migration with version ["
                    + version
                    + "] has already been registered, represented by class ["
                    + migrationVersions.get(version).getClass()
                            .getCanonicalName() + "].");
        }
        migrationVersions.put(version, migration);
        migrations.add(migration);
    }


    public int getMigrationCount() {

        return migrations.size();
    }


    public Version getHighestVersion() {

        Version highestVersion = new Version(0);
        for (Migration migration : migrations) {
            final Version migrationVersion = MigrationUtils.getMigrationVersion(migration.getClass());
            if (highestVersion.isHigherOrEqual(migrationVersion)) {
                continue;
            }
            highestVersion = migrationVersion;
        }
        return highestVersion;
    }


    private boolean versionExists(final Version version) {

        return migrationVersions.containsKey(version);
    }

}
